/**
 * Copyright © 2023-2030 The ruanrongman Authors
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package top.rslly.iot.utility.ai.voice.concentus;

class NoiseShapeAnalysis {

  /* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
  /*
   * non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.)
   */
  /*
   * Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first
   */
  /* coefficient in an array of coefficients, for monic filters. */
  static int warped_gain( /* gain in Q16 */
      int[] coefs_Q24,
      int lambda_Q16,
      int order) {
    int i;
    int gain_Q24;

    lambda_Q16 = -lambda_Q16;
    gain_Q24 = coefs_Q24[order - 1];
    for (i = order - 2; i >= 0; i--) {
      gain_Q24 = Inlines.silk_SMLAWB(coefs_Q24[i], gain_Q24, lambda_Q16);
    }
    gain_Q24 = Inlines.silk_SMLAWB(
        ((int) ((1.0f) * ((long) 1 << (24)) + 0.5))/* Inlines.SILK_CONST(1.0f, 24) */, gain_Q24,
        -lambda_Q16);
    return Inlines.silk_INVERSE32_varQ(gain_Q24, 40);
  }

  /* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
  /* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
  static void limit_warped_coefs(
      int[] coefs_syn_Q24,
      int[] coefs_ana_Q24,
      int lambda_Q16,
      int limit_Q24,
      int order) {
    int i, iter, ind = 0;
    int tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16;
    int nom_Q16, den_Q24;

    /* Convert to monic coefficients */
    lambda_Q16 = -lambda_Q16;
    for (i = order - 1; i > 0; i--) {
      coefs_syn_Q24[i - 1] =
          Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
      coefs_ana_Q24[i - 1] =
          Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
    }
    lambda_Q16 = -lambda_Q16;
    nom_Q16 = Inlines.silk_SMLAWB(
        ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(1.0f, 16) */,
        -(int) lambda_Q16, lambda_Q16);
    den_Q24 = Inlines.silk_SMLAWB(
        ((int) ((1.0f) * ((long) 1 << (24)) + 0.5))/* Inlines.SILK_CONST(1.0f, 24) */,
        coefs_syn_Q24[0], lambda_Q16);
    gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
    den_Q24 = Inlines.silk_SMLAWB(
        ((int) ((1.0f) * ((long) 1 << (24)) + 0.5))/* Inlines.SILK_CONST(1.0f, 24) */,
        coefs_ana_Q24[0], lambda_Q16);
    gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
    for (i = 0; i < order; i++) {
      coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
      coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
    }

    for (iter = 0; iter < 10; iter++) {
      /* Find maximum absolute value */
      maxabs_Q24 = -1;
      for (i = 0; i < order; i++) {
        tmp = Inlines.silk_max(Inlines.silk_abs_int32(coefs_syn_Q24[i]),
            Inlines.silk_abs_int32(coefs_ana_Q24[i]));
        if (tmp > maxabs_Q24) {
          maxabs_Q24 = tmp;
          ind = i;
        }
      }
      if (maxabs_Q24 <= limit_Q24) {
        /* Coefficients are within range - done */
        return;
      }

      /* Convert back to true warped coefficients */
      for (i = 1; i < order; i++) {
        coefs_syn_Q24[i - 1] =
            Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
        coefs_ana_Q24[i - 1] =
            Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
      }
      gain_syn_Q16 = Inlines.silk_INVERSE32_varQ(gain_syn_Q16, 32);
      gain_ana_Q16 = Inlines.silk_INVERSE32_varQ(gain_ana_Q16, 32);
      for (i = 0; i < order; i++) {
        coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
        coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
      }

      /* Apply bandwidth expansion */
      chirp_Q16 = ((int) ((0.99f) * ((long) 1 << (16)) + 0.5))
          /* Inlines.SILK_CONST(0.99f, 16) */ - Inlines.silk_DIV32_varQ(
              Inlines.silk_SMULWB(maxabs_Q24 - limit_Q24,
                  Inlines.silk_SMLABB(
                      ((int) ((0.8f) * ((long) 1 << (10)) + 0.5))/* Inlines.SILK_CONST(0.8f, 10) */,
                      ((int) ((0.1f) * ((long) 1 << (10)) + 0.5))/* Inlines.SILK_CONST(0.1f, 10) */,
                      iter)),
              Inlines.silk_MUL(maxabs_Q24, ind + 1), 22);
      BWExpander.silk_bwexpander_32(coefs_syn_Q24, order, chirp_Q16);
      BWExpander.silk_bwexpander_32(coefs_ana_Q24, order, chirp_Q16);

      /* Convert to monic warped coefficients */
      lambda_Q16 = -lambda_Q16;
      for (i = order - 1; i > 0; i--) {
        coefs_syn_Q24[i - 1] =
            Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
        coefs_ana_Q24[i - 1] =
            Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
      }
      lambda_Q16 = -lambda_Q16;
      nom_Q16 = Inlines.silk_SMLAWB(
          ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(1.0f, 16) */,
          -(int) lambda_Q16, lambda_Q16);
      den_Q24 = Inlines.silk_SMLAWB(
          ((int) ((1.0f) * ((long) 1 << (24)) + 0.5))/* Inlines.SILK_CONST(1.0f, 24) */,
          coefs_syn_Q24[0], lambda_Q16);
      gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
      den_Q24 = Inlines.silk_SMLAWB(
          ((int) ((1.0f) * ((long) 1 << (24)) + 0.5))/* Inlines.SILK_CONST(1.0f, 24) */,
          coefs_ana_Q24[0], lambda_Q16);
      gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
      for (i = 0; i < order; i++) {
        coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
        coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
      }
    }
    Inlines.OpusAssert(false);
  }

  /**
   * ***********************************************************
   */
  /* Compute noise shaping coefficients and initial gain values */
  /**
   * ***********************************************************
   */
  static void silk_noise_shape_analysis(
      SilkChannelEncoder psEnc, /* I/O Encoder state FIX */
      SilkEncoderControl psEncCtrl, /* I/O Encoder control FIX */
      short[] pitch_res, /* I LPC residual from pitch analysis */
      int pitch_res_ptr,
      short[] x, /* I Input signal [ frame_length + la_shape ] */
      int x_ptr) {
    SilkShapeState psShapeSt = psEnc.sShape;
    int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
    int SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
    int nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
    int delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
    int[] auto_corr = new int[SilkConstants.MAX_SHAPE_LPC_ORDER + 1];
    int[] refl_coef_Q16 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
    int[] AR1_Q24 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
    int[] AR2_Q24 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
    short[] x_windowed;
    int pitch_res_ptr2;
    int x_ptr2;

    /* Point to start of first LPC analysis block */
    x_ptr2 = x_ptr - psEnc.la_shape;

    /**
     * *************
     */
    /* GAIN CONTROL */
    /**
     * *************
     */
    SNR_adj_dB_Q7 = psEnc.SNR_dB_Q7;

    /* Input quality is the average of the quality in the lowest two VAD bands */
    psEncCtrl.input_quality_Q14 = (int) Inlines.silk_RSHIFT((int) psEnc.input_quality_bands_Q15[0]
        + psEnc.input_quality_bands_Q15[1], 2);

    /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
    psEncCtrl.coding_quality_Q14 = Inlines.silk_RSHIFT(
        Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(SNR_adj_dB_Q7
            - ((int) ((20.0f) * ((long) 1 << (7)) + 0.5))/* Inlines.SILK_CONST(20.0f, 7) */, 4)),
        1);

    /* Reduce coding SNR during low speech activity */
    if (psEnc.useCBR == 0) {
      b_Q8 = ((int) ((1.0f) * ((long) 1 << (8)) + 0.5))
          /* Inlines.SILK_CONST(1.0f, 8) */ - psEnc.speech_activity_Q8;
      b_Q8 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(b_Q8, 8), b_Q8);
      SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
          Inlines.silk_SMULBB(((int) ((0 - TuningParameters.BG_SNR_DECR_dB) * ((long) 1 << (7))
              + 0.5))/* Inlines.SILK_CONST(0 - TuningParameters.BG_SNR_DECR_dB, 7) */ >> (4 + 1),
              b_Q8), /* Q11 */
          Inlines.silk_SMULWB(
              ((int) ((1.0f) * ((long) 1 << (14)) + 0.5))
                  /* Inlines.SILK_CONST(1.0f, 14) */ + psEncCtrl.input_quality_Q14,
              psEncCtrl.coding_quality_Q14));
      /* Q12 */
    }

    if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED) {
      /* Reduce gains for periodic signals */
      SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
          ((int) ((TuningParameters.HARM_SNR_INCR_dB) * ((long) 1 << (8))
              + 0.5))/* Inlines.SILK_CONST(TuningParameters.HARM_SNR_INCR_dB, 8) */,
          psEnc.LTPCorr_Q15);
    } else {
      /*
       * For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting
       */
      SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
          Inlines.silk_SMLAWB(
              ((int) ((6.0f) * ((long) 1 << (9)) + 0.5))/* Inlines.SILK_CONST(6.0f, 9) */,
              -((int) ((0.4f) * ((long) 1 << (18)) + 0.5))/* Inlines.SILK_CONST(0.4f, 18) */,
              psEnc.SNR_dB_Q7),
          ((int) ((1.0f) * ((long) 1 << (14)) + 0.5))
              /* Inlines.SILK_CONST(1.0f, 14) */ - psEncCtrl.input_quality_Q14);
    }

    /**
     * **********************
     */
    /* SPARSENESS PROCESSING */
    /**
     * **********************
     */
    /* Set quantizer offset */
    if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED) {
      /* Initially set to 0; may be overruled in process_gains(..) */
      psEnc.indices.quantOffsetType = 0;
      psEncCtrl.sparseness_Q8 = 0;
    } else {
      /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
      nSamples = Inlines.silk_LSHIFT(psEnc.fs_kHz, 1);
      energy_variation_Q7 = 0;
      log_energy_prev_Q7 = 0;
      pitch_res_ptr2 = pitch_res_ptr;
      BoxedValueInt boxed_nrg = new BoxedValueInt(0);
      BoxedValueInt boxed_scale = new BoxedValueInt(0);
      for (k =
          0; k < Inlines.silk_SMULBB(SilkConstants.SUB_FRAME_LENGTH_MS, psEnc.nb_subfr) / 2; k++) {
        SumSqrShift.silk_sum_sqr_shift(boxed_nrg, boxed_scale, pitch_res, pitch_res_ptr2, nSamples);
        nrg = boxed_nrg.Val;
        scale = boxed_scale.Val;
        nrg += Inlines.silk_RSHIFT(nSamples, scale);
        /* Q(-scale) */

        log_energy_Q7 = Inlines.silk_lin2log(nrg);
        if (k > 0) {
          energy_variation_Q7 += Inlines.silk_abs(log_energy_Q7 - log_energy_prev_Q7);
        }
        log_energy_prev_Q7 = log_energy_Q7;
        pitch_res_ptr2 += nSamples;
      }

      psEncCtrl.sparseness_Q8 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(
          energy_variation_Q7
              - ((int) ((5.0f) * ((long) 1 << (7)) + 0.5))/* Inlines.SILK_CONST(5.0f, 7) */,
          ((int) ((0.1f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(0.1f, 16) */)), 7);

      /* Set quantization offset depending on sparseness measure */
      if (psEncCtrl.sparseness_Q8 > ((int) ((TuningParameters.SPARSENESS_THRESHOLD_QNT_OFFSET)
          * ((long) 1 << (8)) + 0.5))/*
                                      * Inlines.SILK_CONST(TuningParameters.
                                      * SPARSENESS_THRESHOLD_QNT_OFFSET, 8)
                                      */) {
        psEnc.indices.quantOffsetType = 0;
      } else {
        psEnc.indices.quantOffsetType = 1;
      }

      /* Increase coding SNR for sparse signals */
      SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
          ((int) ((TuningParameters.SPARSE_SNR_INCR_dB) * ((long) 1 << (15))
              + 0.5))/* Inlines.SILK_CONST(TuningParameters.SPARSE_SNR_INCR_dB, 15) */,
          psEncCtrl.sparseness_Q8 - ((int) ((0.5f) * ((long) 1 << (8)) + 0.5))/*
                                                                               * Inlines.SILK_CONST(
                                                                               * 0.5f, 8)
                                                                               */);
    }

    /**
     * ****************************
     */
    /* Control bandwidth expansion */
    /**
     * ****************************
     */
    /* More BWE for signals with high prediction gain */
    strength_Q16 =
        Inlines.silk_SMULWB(psEncCtrl.predGain_Q16,
            ((int) ((TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION) * ((long) 1 << (16))
                + 0.5))/*
                        * Inlines.SILK_CONST(TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION, 16)
                        */);
    BWExp1_Q16 = BWExp2_Q16 =
        Inlines.silk_DIV32_varQ(((int) ((TuningParameters.BANDWIDTH_EXPANSION) * ((long) 1 << (16))
            + 0.5))/* Inlines.SILK_CONST(TuningParameters.BANDWIDTH_EXPANSION, 16) */,
            Inlines.silk_SMLAWW(
                ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(1.0f, 16) */,
                strength_Q16, strength_Q16),
            16);
    delta_Q16 = Inlines.silk_SMULWB(
        ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(1.0f, 16) */ - Inlines
            .silk_SMULBB(3, psEncCtrl.coding_quality_Q14),
        ((int) ((TuningParameters.LOW_RATE_BANDWIDTH_EXPANSION_DELTA) * ((long) 1 << (16))
            + 0.5))/* Inlines.SILK_CONST(TuningParameters.LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16) */);
    BWExp1_Q16 = Inlines.silk_SUB32(BWExp1_Q16, delta_Q16);
    BWExp2_Q16 = Inlines.silk_ADD32(BWExp2_Q16, delta_Q16);
    /* BWExp1 will be applied after BWExp2, so make it relative */
    BWExp1_Q16 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(BWExp1_Q16, 14),
        Inlines.silk_RSHIFT(BWExp2_Q16, 2));

    if (psEnc.warping_Q16 > 0) {
      /*
       * Slightly more warping in analysis will move quantization noise up in frequency, where it's
       * better masked
       */
      warping_Q16 = Inlines.silk_SMLAWB(psEnc.warping_Q16, (int) psEncCtrl.coding_quality_Q14,
          ((int) ((0.01f) * ((long) 1 << (18)) + 0.5))/* Inlines.SILK_CONST(0.01f, 18) */);
    } else {
      warping_Q16 = 0;
    }

    /**
     * *****************************************
     */
    /* Compute noise shaping AR coefs and gains */
    /**
     * *****************************************
     */
    x_windowed = new short[psEnc.shapeWinLength];
    for (k = 0; k < psEnc.nb_subfr; k++) {
      /* Apply window: sine slope followed by flat part followed by cosine slope */
      int shift, slope_part, flat_part;
      flat_part = psEnc.fs_kHz * 3;
      slope_part = Inlines.silk_RSHIFT(psEnc.shapeWinLength - flat_part, 1);

      ApplySineWindow.silk_apply_sine_window(x_windowed, 0, x, x_ptr2, 1, slope_part);
      shift = slope_part;
      System.arraycopy(x, x_ptr2 + shift, x_windowed, shift, flat_part);
      shift += flat_part;
      ApplySineWindow.silk_apply_sine_window(x_windowed, shift, x, x_ptr2 + shift, 2, slope_part);

      /* Update pointer: next LPC analysis block */
      x_ptr2 += psEnc.subfr_length;
      BoxedValueInt scale_boxed = new BoxedValueInt(scale);
      if (psEnc.warping_Q16 > 0) {
        /* Calculate warped auto correlation */
        Autocorrelation.silk_warped_autocorrelation(auto_corr, scale_boxed, x_windowed, warping_Q16,
            psEnc.shapeWinLength, psEnc.shapingLPCOrder);
      } else {
        /* Calculate regular auto correlation */
        Autocorrelation.silk_autocorr(auto_corr, scale_boxed, x_windowed, psEnc.shapeWinLength,
            psEnc.shapingLPCOrder + 1);
      }
      scale = scale_boxed.Val;

      /* Add white noise, as a fraction of energy */
      auto_corr[0] = Inlines.silk_ADD32(auto_corr[0], Inlines.silk_max_32(
          Inlines.silk_SMULWB(Inlines.silk_RSHIFT(auto_corr[0], 4),
              ((int) ((TuningParameters.SHAPE_WHITE_NOISE_FRACTION) * ((long) 1 << (20))
                  + 0.5))/* Inlines.SILK_CONST(TuningParameters.SHAPE_WHITE_NOISE_FRACTION, 20) */),
          1));

      /* Calculate the reflection coefficients using schur */
      nrg = Schur.silk_schur64(refl_coef_Q16, auto_corr, psEnc.shapingLPCOrder);
      Inlines.OpusAssert(nrg >= 0);

      /* Convert reflection coefficients to prediction coefficients */
      K2A.silk_k2a_Q16(AR2_Q24, refl_coef_Q16, psEnc.shapingLPCOrder);

      Qnrg = -scale;
      /* range: -12...30 */
      Inlines.OpusAssert(Qnrg >= -12);
      Inlines.OpusAssert(Qnrg <= 30);

      /* Make sure that Qnrg is an even number */
      if ((Qnrg & 1) != 0) {
        Qnrg -= 1;
        nrg >>= 1;
      }

      tmp32 = Inlines.silk_SQRT_APPROX(nrg);
      Qnrg >>= 1;
      /* range: -6...15 */

      psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(tmp32, 16 - Qnrg);

      if (psEnc.warping_Q16 > 0) {
        /* Adjust gain for warping */
        gain_mult_Q16 = warped_gain(AR2_Q24, warping_Q16, psEnc.shapingLPCOrder);
        Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0);
        if (Inlines.silk_SMULWW(Inlines.silk_RSHIFT_ROUND(psEncCtrl.Gains_Q16[k], 1),
            gain_mult_Q16) >= (Integer.MAX_VALUE >> 1)) {
          psEncCtrl.Gains_Q16[k] = Integer.MAX_VALUE;
        } else {
          psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16);
        }
      }

      /* Bandwidth expansion for synthesis filter shaping */
      BWExpander.silk_bwexpander_32(AR2_Q24, psEnc.shapingLPCOrder, BWExp2_Q16);

      /* Compute noise shaping filter coefficients */
      System.arraycopy(AR2_Q24, 0, AR1_Q24, 0, psEnc.shapingLPCOrder);

      /* Bandwidth expansion for analysis filter shaping */
      Inlines.OpusAssert(BWExp1_Q16 <= ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))/*
                                                                                   * Inlines.
                                                                                   * SILK_CONST(1.
                                                                                   * 0f, 16)
                                                                                   */);
      BWExpander.silk_bwexpander_32(AR1_Q24, psEnc.shapingLPCOrder, BWExp1_Q16);

      /* Ratio of prediction gains, in energy domain */
      pre_nrg_Q30 =
          LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR2_Q24, psEnc.shapingLPCOrder);
      nrg = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR1_Q24, psEnc.shapingLPCOrder);

      /*
       * psEncCtrl.GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg /
       * nrg;
       */
      pre_nrg_Q30 = Inlines.silk_LSHIFT32(Inlines.silk_SMULWB(pre_nrg_Q30,
          ((int) ((0.7f) * ((long) 1 << (15)) + 0.5))/* Inlines.SILK_CONST(0.7f, 15) */), 1);
      psEncCtrl.GainsPre_Q14[k] = (int) ((int) ((0.3f) * ((long) 1 << (14)) + 0.5))
          /* Inlines.SILK_CONST(0.3f, 14) */ + Inlines.silk_DIV32_varQ(pre_nrg_Q30, nrg, 14);

      /* Convert to monic warped prediction coefficients and limit absolute values */
      limit_warped_coefs(AR2_Q24, AR1_Q24, warping_Q16,
          ((int) ((3.999f) * ((long) 1 << (24)) + 0.5))/* Inlines.SILK_CONST(3.999f, 24) */,
          psEnc.shapingLPCOrder);

      /* Convert from Q24 to Q13 and store in int16 */
      for (i = 0; i < psEnc.shapingLPCOrder; i++) {
        psEncCtrl.AR1_Q13[k * SilkConstants.MAX_SHAPE_LPC_ORDER + i] =
            (short) Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR1_Q24[i], 11));
        psEncCtrl.AR2_Q13[k * SilkConstants.MAX_SHAPE_LPC_ORDER + i] =
            (short) Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR2_Q24[i], 11));
      }
    }

    /**
     * **************
     */
    /* Gain tweaking */
    /**
     * **************
     */
    /* Increase gains during low speech activity and put lower limit on gains */
    gain_mult_Q16 = Inlines.silk_log2lin(-Inlines.silk_SMLAWB(
        -((int) ((16.0f) * ((long) 1 << (7))
            + 0.5))/* Inlines.SILK_CONST(16.0f, 7) */,
        SNR_adj_dB_Q7, ((int) ((0.16f) * ((long) 1 << (16)) + 0.5))/*
                                                                    * Inlines.SILK_CONST(0.16f, 16)
                                                                    */));
    gain_add_Q16 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(
        ((int) ((16.0f) * ((long) 1 << (7)) + 0.5))/* Inlines.SILK_CONST(16.0f, 7) */,
        ((int) ((SilkConstants.MIN_QGAIN_DB) * ((long) 1 << (7))
            + 0.5))/* Inlines.SILK_CONST(SilkConstants.MIN_QGAIN_DB, 7) */,
        ((int) ((0.16f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(0.16f, 16) */));
    Inlines.OpusAssert(gain_mult_Q16 > 0);
    for (k = 0; k < psEnc.nb_subfr; k++) {
      psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16);
      Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0);
      psEncCtrl.Gains_Q16[k] = Inlines.silk_ADD_POS_SAT32(psEncCtrl.Gains_Q16[k], gain_add_Q16);
    }

    gain_mult_Q16 =
        ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))
            /* Inlines.SILK_CONST(1.0f, 16) */ + Inlines.silk_RSHIFT_ROUND(
                Inlines.silk_MLA(((int) ((TuningParameters.INPUT_TILT) * ((long) 1 << (26))
                    + 0.5))/* Inlines.SILK_CONST(TuningParameters.INPUT_TILT, 26) */,
                    psEncCtrl.coding_quality_Q14,
                    ((int) ((TuningParameters.HIGH_RATE_INPUT_TILT) * ((long) 1 << (12))
                        + 0.5))/* Inlines.SILK_CONST(TuningParameters.HIGH_RATE_INPUT_TILT, 12) */),
                10);
    for (k = 0; k < psEnc.nb_subfr; k++) {
      psEncCtrl.GainsPre_Q14[k] = Inlines.silk_SMULWB(gain_mult_Q16, psEncCtrl.GainsPre_Q14[k]);
    }

    /**
     * *********************************************
     */
    /* Control low-frequency shaping and noise tilt */
    /**
     * *********************************************
     */
    /* Less low frequency shaping for noisy inputs */
    strength_Q16 = Inlines.silk_MUL(((int) ((TuningParameters.LOW_FREQ_SHAPING) * ((long) 1 << (4))
        + 0.5))/* Inlines.SILK_CONST(TuningParameters.LOW_FREQ_SHAPING, 4) */, Inlines.silk_SMLAWB(
            ((int) ((1.0f) * ((long) 1 << (12)) + 0.5))/* Inlines.SILK_CONST(1.0f, 12) */,
            ((int) ((TuningParameters.LOW_QUALITY_LOW_FREQ_SHAPING_DECR) * ((long) 1 << (13))
                + 0.5))/*
                        * Inlines.SILK_CONST(TuningParameters.LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13)
                        */,
            psEnc.input_quality_bands_Q15[0] - ((int) ((1.0f) * ((long) 1 << (15)) + 0.5))/*
                                                                                           * Inlines
                                                                                           * .
                                                                                           * SILK_CONST
                                                                                           * (1.0f,
                                                                                           * 15)
                                                                                           */));
    strength_Q16 = Inlines.silk_RSHIFT(Inlines.silk_MUL(strength_Q16, psEnc.speech_activity_Q8), 8);
    if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED) {
      /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
      /*
       * f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10,
       * 1])
       */
      int fs_kHz_inv = Inlines.silk_DIV32_16(
          ((int) ((0.2f) * ((long) 1 << (14)) + 0.5))/* Inlines.SILK_CONST(0.2f, 14) */,
          psEnc.fs_kHz);
      for (k = 0; k < psEnc.nb_subfr; k++) {
        b_Q14 = fs_kHz_inv + Inlines.silk_DIV32_16(
            ((int) ((3.0f) * ((long) 1 << (14)) + 0.5))/* Inlines.SILK_CONST(3.0f, 14) */,
            psEncCtrl.pitchL[k]);
        /* Pack two coefficients in one int32 */
        psEncCtrl.LF_shp_Q14[k] = Inlines.silk_LSHIFT(((int) ((1.0f) * ((long) 1 << (14)) + 0.5))
            /* Inlines.SILK_CONST(1.0f, 14) */ - b_Q14 - Inlines.silk_SMULWB(strength_Q16, b_Q14),
            16);
        psEncCtrl.LF_shp_Q14[k] |=
            (b_Q14 - ((int) ((1.0f) * ((long) 1 << (14)) + 0.5))/* Inlines.SILK_CONST(1.0f, 14) */)
                & 0xFFFF;
      }
      Inlines.OpusAssert(((int) ((TuningParameters.HARM_HP_NOISE_COEF) * ((long) 1 << (24))
          + 0.5))/* Inlines.SILK_CONST(TuningParameters.HARM_HP_NOISE_COEF, 24) */ < ((int) ((0.5f)
              * ((long) 1 << (24)) + 0.5))/* Inlines.SILK_CONST(0.5f, 24) */);
      /* Guarantees that second argument to SMULWB() is within range of an short */
      Tilt_Q16 = -((int) ((TuningParameters.HP_NOISE_COEF) * ((long) 1 << (16)) + 0.5))
          /* Inlines.SILK_CONST(TuningParameters.HP_NOISE_COEF, 16) */ - Inlines.silk_SMULWB(
              ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))
                  /* Inlines.SILK_CONST(1.0f, 16) */ - ((int) ((TuningParameters.HP_NOISE_COEF)
                      * ((long) 1 << (16)) + 0.5))/*
                                                   * Inlines.SILK_CONST(TuningParameters.
                                                   * HP_NOISE_COEF, 16)
                                                   */,
              Inlines.silk_SMULWB(
                  ((int) ((TuningParameters.HARM_HP_NOISE_COEF) * ((long) 1 << (24))
                      + 0.5))/* Inlines.SILK_CONST(TuningParameters.HARM_HP_NOISE_COEF, 24) */,
                  psEnc.speech_activity_Q8));
    } else {
      b_Q14 = Inlines.silk_DIV32_16(21299, psEnc.fs_kHz);
      /* 1.3_Q0 = 21299_Q14 */
      /* Pack two coefficients in one int32 */
      psEncCtrl.LF_shp_Q14[0] = Inlines.silk_LSHIFT(
          ((int) ((1.0f) * ((long) 1 << (14)) + 0.5))/* Inlines.SILK_CONST(1.0f, 14) */ - b_Q14
              - Inlines.silk_SMULWB(strength_Q16, Inlines.silk_SMULWB(
                  ((int) ((0.6f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(0.6f, 16) */,
                  b_Q14)),
          16);
      psEncCtrl.LF_shp_Q14[0] |= (b_Q14 - ((int) ((1.0f) * ((long) 1 << (14)) + 0.5))/*
                                                                                      * Inlines.
                                                                                      * SILK_CONST(1
                                                                                      * .0f, 14)
                                                                                      */) & 0xFFFF;
      for (k = 1; k < psEnc.nb_subfr; k++) {
        psEncCtrl.LF_shp_Q14[k] = psEncCtrl.LF_shp_Q14[0];
      }
      Tilt_Q16 = -((int) ((TuningParameters.HP_NOISE_COEF) * ((long) 1 << (16)) + 0.5))/*
                                                                                        * Inlines.
                                                                                        * SILK_CONST
                                                                                        * (
                                                                                        * TuningParameters
                                                                                        * .
                                                                                        * HP_NOISE_COEF,
                                                                                        * 16)
                                                                                        */;
    }

    /**
     * *************************
     */
    /* HARMONIC SHAPING CONTROL */
    /**
     * *************************
     */
    /* Control boosting of harmonic frequencies */
    HarmBoost_Q16 =
        Inlines.silk_SMULWB(
            Inlines.silk_SMULWB(
                ((int) ((1.0f) * ((long) 1 << (17))
                    + 0.5))
                    /* Inlines.SILK_CONST(1.0f, 17) */ - Inlines
                        .silk_LSHIFT(psEncCtrl.coding_quality_Q14, 3),
                psEnc.LTPCorr_Q15),
            ((int) ((TuningParameters.LOW_RATE_HARMONIC_BOOST) * ((long) 1 << (16)) + 0.5))/*
                                                                                            * Inlines
                                                                                            * .
                                                                                            * SILK_CONST
                                                                                            * (
                                                                                            * TuningParameters
                                                                                            * .
                                                                                            * LOW_RATE_HARMONIC_BOOST,
                                                                                            * 16)
                                                                                            */);

    /* More harmonic boost for noisy input signals */
    HarmBoost_Q16 = Inlines.silk_SMLAWB(HarmBoost_Q16,
        ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))/* Inlines.SILK_CONST(1.0f, 16) */ - Inlines
            .silk_LSHIFT(psEncCtrl.input_quality_Q14, 2),
        ((int) ((TuningParameters.LOW_INPUT_QUALITY_HARMONIC_BOOST) * ((long) 1 << (16))
            + 0.5))/* Inlines.SILK_CONST(TuningParameters.LOW_INPUT_QUALITY_HARMONIC_BOOST, 16) */);

    if (SilkConstants.USE_HARM_SHAPING != 0
        && psEnc.indices.signalType == SilkConstants.TYPE_VOICED) {
      /* More harmonic noise shaping for high bitrates or noisy input */
      HarmShapeGain_Q16 =
          Inlines.silk_SMLAWB(((int) ((TuningParameters.HARMONIC_SHAPING) * ((long) 1 << (16))
              + 0.5))/* Inlines.SILK_CONST(TuningParameters.HARMONIC_SHAPING, 16) */,
              ((int) ((1.0f) * ((long) 1 << (16)) + 0.5))
                  /* Inlines.SILK_CONST(1.0f, 16) */ - Inlines.silk_SMULWB(
                      ((int) ((1.0f) * ((long) 1 << (18)) + 0.5))
                          /* Inlines.SILK_CONST(1.0f, 18) */ - Inlines
                              .silk_LSHIFT(psEncCtrl.coding_quality_Q14, 4),
                      psEncCtrl.input_quality_Q14),
              ((int) ((TuningParameters.HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING)
                  * ((long) 1 << (16)) + 0.5))/*
                                               * Inlines.SILK_CONST(TuningParameters.
                                               * HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16)
                                               */);

      /* Less harmonic noise shaping for less periodic signals */
      HarmShapeGain_Q16 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(HarmShapeGain_Q16, 1),
          Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(psEnc.LTPCorr_Q15, 15)));
    } else {
      HarmShapeGain_Q16 = 0;
    }

    /**
     * **********************
     */
    /* Smooth over subframes */
    /**
     * **********************
     */
    for (k = 0; k < SilkConstants.MAX_NB_SUBFR; k++) {
      psShapeSt.HarmBoost_smth_Q16 = Inlines.silk_SMLAWB(psShapeSt.HarmBoost_smth_Q16,
          HarmBoost_Q16 - psShapeSt.HarmBoost_smth_Q16, ((int) ((TuningParameters.SUBFR_SMTH_COEF)
              * ((long) 1 << (16)) + 0.5))/*
                                           * Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF,
                                           * 16)
                                           */);
      psShapeSt.HarmShapeGain_smth_Q16 = Inlines.silk_SMLAWB(psShapeSt.HarmShapeGain_smth_Q16,
          HarmShapeGain_Q16 - psShapeSt.HarmShapeGain_smth_Q16,
          ((int) ((TuningParameters.SUBFR_SMTH_COEF) * ((long) 1 << (16)) + 0.5))/*
                                                                                  * Inlines.
                                                                                  * SILK_CONST(
                                                                                  * TuningParameters
                                                                                  * .
                                                                                  * SUBFR_SMTH_COEF,
                                                                                  * 16)
                                                                                  */);
      psShapeSt.Tilt_smth_Q16 = Inlines.silk_SMLAWB(psShapeSt.Tilt_smth_Q16,
          Tilt_Q16 - psShapeSt.Tilt_smth_Q16, ((int) ((TuningParameters.SUBFR_SMTH_COEF)
              * ((long) 1 << (16)) + 0.5))/*
                                           * Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF,
                                           * 16)
                                           */);

      psEncCtrl.HarmBoost_Q14[k] = (int) Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmBoost_smth_Q16, 2);
      psEncCtrl.HarmShapeGain_Q14[k] =
          (int) Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmShapeGain_smth_Q16, 2);
      psEncCtrl.Tilt_Q14[k] = (int) Inlines.silk_RSHIFT_ROUND(psShapeSt.Tilt_smth_Q16, 2);
    }
  }
}
